home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / cppcom.zip / UART.CPP < prev    next >
C/C++ Source or Header  |  1991-05-25  |  10KB  |  455 lines

  1. /***************************************************************************
  2. These C++ classes are copyright 1990, by William Herrera.
  3. All those who put this code or its derivatives in a commercial product MUST
  4. mention this copyright in their documentation for users of the products in
  5. which this code or its derivative classes are used.  Otherwise, this code
  6. may be freely distributed and freely used for any purpose.
  7.  
  8. Enhancements: 1991 by David Orme
  9.     *  General cleanup.
  10.             - I/O now takes advantage of C++ overloading.
  11.             - Serial port I/O functionality now only in Serial class.
  12.             - Modem functionality now only in Modem class.
  13.     *  Possible to easily implement file Xfr prots now.
  14.     *  CCITT CRC-16 class added                            -- 2-20-1991
  15.     *  BIOS Timer class added                                -- 2-22-1991
  16.     *  Optional timeout on all input routines added    -- 2-25-1991
  17.  
  18. ***************************************************************************/
  19.  
  20. // File uart.cpp, class definitions for the uart class.
  21. // By William Herrera.
  22.  
  23. // See your modem manual (I used MultiTech's) or the IBM Technical
  24. // reference manual for more information on the 8250 UART used in the PC.
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28.  
  29.  
  30. #include "uart.hpp"
  31.  
  32.  
  33. // C++ 2.0 requires that static data members be declared globally
  34.  
  35. char uart::old_intmask[NUM_PORTS];
  36. char uart::old_MCR[NUM_PORTS];
  37. char uart::old_IER[NUM_PORTS];
  38.  
  39. const int uart::portvector_num[NUM_PORTS] = { 0xC, 0xB, 0xC, 0xB };
  40.  
  41. const char uart::intmaskbit[NUM_PORTS] = { 0x10, 0x08, 0x10, 0x08 };
  42.  
  43. #ifdef __TURBOC__
  44. DRIVER uart::old_driver[NUM_PORTS] = { NULL, NULL, NULL, NULL };
  45. #else ifdef __ZTC__
  46. void far * uart::old_driver[NUM_PORTS] = { NULL, NULL, NULL, NULL };
  47. #endif
  48.  
  49. uart::uart() { ; }
  50.  
  51. uart::~uart() { ; }
  52.  
  53.  
  54. // the following function sets up the PC for interrupt-driven serial
  55. // communications through the UART.  Returns 0 for success, -1 for
  56. // port disallowed, -2 for uart interrupts not resettable.
  57. int uart::RegisterDriver(int portnum, DRIVER driv)
  58. {
  59.     int retval;
  60.     if (
  61.         (portnum < 1) || (portnum > NUM_PORTS) ||
  62.             (old_driver[portnum - 1] != NULL) )
  63.     {
  64.         fputs("uart::RegisterDriver() cannot set port requested.\n",
  65.                 stderr);
  66.         retval = -1;
  67.     }
  68.     else
  69.     {
  70.         disable();
  71.         // Hardware interrupts off til we change the settings.
  72.         // Make sure DLAB of LSR is 0 to allow access to IER and MCR.
  73.         SetLCR_DLAB(false);
  74.         // Save old IER and MCR.
  75.         old_IER[portnum -1] = GetIER();
  76.         old_MCR[portnum- 1] = GetMCR();
  77.         // Then check the UART for accessibility.
  78.         SetIER(0);
  79.         if (GetIER() != 0)
  80.         {
  81.             fputs("uart error:  unable to reset IER\n", stderr);
  82.             retval = -2;
  83.         }
  84.         else
  85.         {
  86.             // save the old interrupt mask.
  87.             old_intmask[portnum - 1] = inportb(0x21);
  88.  
  89.             // reset vector to point to our handler.
  90. #ifdef __TURBOC__
  91.             old_driver[portnum - 1] = getvect(portvector_num[portnum - 1]);
  92.             setvect(portvector_num[portnum - 1], driv);
  93. #else ifdef __ZTC__
  94.             unsigned int iseg, ioff;
  95.             int_getvector(portvector_num[portnum - 1], &ioff, &iseg);
  96.             old_driver[portnum - 1] = MK_FP(iseg, ioff);
  97.             int_intercept(portvector_num[portnum - 1], driv, 0);
  98. #endif
  99.             SetMCR(9);    // turn on DTR and interrupts by modem (1|8).
  100.             SetIER(13);    // turn on data ready, line, modem ints (1|4|8).
  101.  
  102.             // Now enable controller for serial port interrupts.
  103.             outportb( 0x21, (inportb(0x21) & ~(intmaskbit[portnum - 1])) );
  104.  
  105.             // set speed to a default baud rate of 19200.
  106.             SetSpeed(19200);
  107.             // Set port to default parameters of 8 data, 1 stop, no parity.
  108.             SetParity(NOPAR);
  109.             SetWordLength(8);
  110.             SetStopBits(1);
  111.  
  112.             retval = 0;
  113.         }
  114.         enable();
  115.     }
  116.     return retval;
  117. }
  118.  
  119. // This function resets the interrupt controller and UART and
  120. // generally cleans up after the RegisterDriver function.
  121. // Returns 0 on success, -1 on port not restorable.
  122. int uart::RestoreDriver(int portnum)
  123. {
  124.     int retval;
  125.  
  126.     if ( (portnum < 1) || (portnum > NUM_PORTS) ||
  127.             (old_driver[portnum - 1] == NULL) )
  128.     {
  129.         fputs("UART Error:  Cannot restore port.\n", stderr);
  130.         retval = -1;
  131.     }
  132.     else
  133.     {
  134.         // reset the interrupt vector.
  135.         disable();
  136. #ifdef __TURBOC__
  137.         setvect(portvector_num[portnum - 1], old_driver[portnum - 1]);
  138. #else ifdef __ZTC__
  139.         int_restore(portvector_num[portnum - 1]);
  140. #endif
  141.         // reset the i8259 mask to its original state.
  142.         outportb(0x21, old_intmask[portnum - 1]);
  143.         // reset UART registers.
  144.         SetIER(old_IER[portnum -1]);
  145.         SetMCR(old_MCR[portnum - 1]);
  146.         enable();
  147.         old_driver[portnum - 1] = NULL;
  148.         retval = 0;
  149.     }
  150.     return retval;
  151. }
  152.  
  153. char uart::GetLCR()
  154. {
  155.     return inportb(LCR());
  156. }
  157.  
  158. char uart::GetDLL()
  159. {
  160.     return inportb(DLL());
  161. }
  162.  
  163. char uart::GetDLM()
  164. {
  165.     return inportb(DLM());
  166. }
  167.  
  168. char uart::GetLSR()
  169. {
  170.     return inportb(LSR());
  171. }
  172.  
  173. char uart::GetMCR()
  174. {
  175.     return inportb(MCR());
  176. }
  177.  
  178. char uart::GetMSR()
  179. {
  180.     return inportb(MSR());
  181. }
  182.  
  183. char uart::GetRBR()
  184. {
  185.     return inportb(RBR());
  186. }
  187.  
  188. char uart::GetIER()
  189. {
  190.     return inportb(IER());
  191. }
  192.  
  193. char uart::GetIIR()
  194. {
  195.     return inportb(IIR());
  196. }
  197.  
  198. boolean uart::GetLSR_THRE()
  199. {
  200.     return (GetLSR() & 32) ? true : false;
  201. }
  202.  
  203. void uart::SetLCR(char byte)
  204. {
  205.     outportb(LCR(), byte);
  206. }
  207.  
  208. void uart::SetDLL(char byte)
  209. {
  210.     outportb(DLL(), byte);
  211. }
  212.  
  213. void uart::SetDLM(char byte)
  214. {
  215.     outportb(DLM(), byte);
  216. }
  217.  
  218. void uart::SetLSR(char byte)
  219. {
  220.     outportb(LSR(), byte);
  221. }
  222.  
  223. void uart::SetMCR(char byte)
  224. {
  225.     outportb(MCR(), byte);
  226. }
  227.  
  228. void uart::SetMSR(char byte)
  229. {
  230.     outportb(MSR(), byte);
  231. }
  232.  
  233. void uart::SetTHR(char byte)
  234. {
  235.     outportb(THR(), byte);
  236. }
  237.  
  238. void uart::SetIER(char byte)
  239. {
  240.     outportb(IER(), byte);
  241. }
  242.  
  243. void uart::SetIER_Recieve(boolean bit)
  244. {
  245.     SetIER( (bit) ? GetIER() | 1 : GetIER() & (~1) );
  246. }
  247.  
  248. void uart::SetIER_Transmit(boolean bit)
  249. {
  250.     SetIER( (bit) ? GetIER() | 2 : GetIER() & (~2) );
  251. }
  252.  
  253. void uart::SetIER_Line(boolean bit)
  254. {
  255.     SetIER( (bit) ? GetIER() | 4 : GetIER() & (~4) );
  256. }
  257.  
  258. void uart::SetIER_Modem(boolean bit)
  259. {
  260.     SetIER( (bit) ? GetIER() | 8 : GetIER() & (~8) );
  261. }
  262.  
  263. void uart::SetLCR_DLAB(boolean bit)
  264. {
  265.     SetLCR( (bit) ? GetLCR() | 128 : GetLCR() & (~128) );
  266. }
  267.  
  268. void uart::SetLSR_DR(boolean bit)
  269. {
  270.     SetLSR( (bit) ? GetLSR() | 1 : GetLSR() & (~1) );
  271. }
  272.  
  273. void uart::SetBaudRate(int speed)
  274. {
  275.     int divisor = (int)(115200L / (long)speed);
  276.     char lsb = divisor & 0xFF;
  277.     char msb = (divisor >> 8) & 0xFF;
  278.     SetLCR_DLAB(true);
  279.     SetDLL(lsb);
  280.     SetDLM(msb);
  281.     SetLCR_DLAB(false);
  282. }
  283.  
  284. int uart::GetBaudRate()
  285. {
  286.     SetLCR_DLAB(true);
  287.     int lsb = GetDLL() & 0xFF;
  288.     int msb = GetDLM() & 0xFF;
  289.     SetLCR_DLAB(false);
  290.     return ( (int) (115200L / ((long)(msb << 8) + (long)lsb)) );
  291. }
  292.  
  293. void uart::SetParity(parity_t p)
  294. {
  295.     SetLCR( (GetLCR() & 0xC7) | p);
  296. }
  297.  
  298. parity_t uart::GetParity()
  299. {
  300.     return (parity_t)(GetLCR() & 0x38);
  301. }
  302.  
  303. void uart::SetWordLength(int len)
  304. {
  305.     SetLCR( (GetLCR() & 0xFC) | ((len - 5) & 3) );
  306. }
  307.  
  308. int uart::GetWordLength()
  309. {
  310.     return (GetLCR() & 3) + 5;
  311. }
  312.  
  313. void uart::SetStopBits(int num)
  314. {
  315.     SetLCR( (GetLCR() & 0xFB) | ((num == 1) ? 0 : 4) );
  316. }
  317.  
  318. int uart::GetStopBits()
  319. {
  320.     return (GetLCR() & 4) ? 1 : 2;
  321. }
  322.  
  323. void uart::SetBreak()
  324. {
  325.     SetLCR(GetLCR() | 64);
  326. }
  327.  
  328. void uart::StopBreak()
  329. {
  330.     SetLCR(GetLCR() & (~64));
  331. }
  332.  
  333. void uart::Pause(int msec)
  334. {
  335.     // assumes the PC BIOS tick is 18.2 per second, or
  336.     // 55 msec per tick.
  337.     // DO NOT call this from an interrupt driver that uses the clock!
  338.     union REGS regs;
  339.     regs.x.ax = 0;
  340.     int86(0x1A, ®s, ®s);
  341.     int startcount = regs.x.dx;
  342.     int endcount = startcount + (msec / 55);
  343.     int i = startcount;
  344.     while(i < endcount && i >= startcount)
  345.     {
  346.         regs.x.ax = 0;
  347.         int86(0x1A, ®s, ®s);
  348.         i = regs.x.dx;
  349.     }
  350. }
  351.  
  352. void uart::Break(int msec)
  353. {
  354.     // assumes the PC BIOS tick is 18.2 per second, or
  355.     // 55 msec per tick.
  356.     // DO NOT call this from an interrupt driver that uses the clock!
  357.     SetBreak();
  358.     Pause(msec);
  359.     StopBreak();
  360. }
  361.  
  362. void uart::SetCTS(boolean bit)
  363. {
  364.     SetMSR( (bit) ? (GetMSR() | 16) : (GetMSR() & (~16)) );
  365. }
  366.  
  367. void uart::SetDSR(boolean bit)
  368. {
  369.     SetMSR( (bit) ? (GetMSR() | 32) : (GetMSR() & (~32)) );
  370. }
  371.  
  372. boolean uart::CarrierPresent()
  373. {
  374.     // actually tests RLSD, bit 7 of MSR.
  375.     return (GetMSR() & 128) ? true : false;
  376. }
  377.  
  378. void uart::SetDTR(boolean bit)
  379. {
  380.     SetMCR( (bit) ? (GetMCR() | 1) : (GetMCR() & (~1)) );
  381. }
  382.  
  383. boolean uart::GetDTR()
  384. {
  385.     return (GetMCR() & 1) ? true : false;
  386. }
  387.  
  388. com_interrupt_t uart::GetIntrType()
  389. {
  390.     int type = (int)GetIIR() & 0xFF;
  391.     if(type & 1)
  392.         return NONE_PENDING;
  393.     int r;
  394.     switch(type)
  395.     {
  396.         case 0:
  397.             r = GetMSR();
  398.             if ((r & 4) != 0)
  399.                 return RING;
  400.             else if ((r & 128) != 0)
  401.                 return CARRIER;
  402.             else
  403.                 return NO_CARRIER;
  404.         case 2:
  405.             r = GetLSR();
  406.             if ((r & 32) != 0)  // THRE
  407.                 return TRANSMIT_READY;
  408.             else
  409.                 return TRANSMIT_FALSE_ALARM;
  410.         case 4:
  411.             return RECEIVE_READY;
  412.         case 6:
  413.             r = GetLSR();
  414.             if ((r & 2) != 0)    //
  415.                 return OVERRUN_ERROR;
  416.             else if ((r & 4) != 0)
  417.                 return PARITY_ERROR;
  418.             else if ((r & 8) != 0)
  419.                 return FRAMING_ERROR;
  420.             else if ((r & 16) != 0)
  421.                 return BREAK_RECEIVED;
  422.             else
  423.                 return UNKNOWN_ERROR;
  424.         default :
  425.             return UNKNOWN_ERROR;
  426.     }
  427. }
  428.  
  429.  
  430. int uart::GetChar()
  431. {
  432.     // note: for this method to work, SetLCR_DLAB(false) must be called.
  433.     return (GetLSR() & 1) ? ( (int)inportb(RBR()) & 0x00FF ) : -1;
  434. }
  435.  
  436. void uart:: SendChar(char ch)
  437. {
  438.     // note: for this method to work, SetLCR_DLAB(false) must be called.
  439.     // this method works only if there is room in the transmit register.
  440.     outportb(THR(), ch);
  441. }
  442.  
  443. void uart::TransmitChar(char ch)
  444. {
  445.     // similar to last one -- allows other to be overloaded separately
  446.     outportb(THR(), ch);
  447. }
  448.  
  449. int uart::ReceiveChar()
  450. {
  451.     // similar to GetChar() -- allows other to be overloaded separately
  452.     // note: for this method to work, SetLCR_DLAB(false) must be called.
  453.     return (GetLSR() & 1) ? ( (int)inportb(RBR()) & 0x00FF ) : -1;
  454. }
  455.